package carcassonne.lobby;

import carcassonne.game.player.PlayerManager;
import carcassonne.game.player.PlayerRole;
import carcassonne.utils.StringUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelGroup;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class RoomManager {

    private static RoomManager instance;

    public static RoomManager GetInstance() {
        if (instance == null) instance = new RoomManager();
        return instance;
    }

    public Map<String, RoomInfo> PrepareRooms = new ConcurrentHashMap<>();

    /**
     * channel id 与 Room 之间的映射集合
     */
    public Map<ChannelId, String> ChannelRoomMapping = new ConcurrentHashMap<>();

    public Map<String, Room> Rooms = new ConcurrentHashMap<>();

    private RoomManager() {
    }

    public String PrepareRoom(RoomInfo roomInfo) {
        String id = "room:" + UUID.randomUUID().toString();
        roomInfo.id = id;
        PrepareRooms.put(id, roomInfo);
        return id;
    }

    public boolean HasPreparedRoom(String id) {
        if (StringUtils.IsNullOrEmpty(id)) return false;
        if (!PrepareRooms.containsKey(id)) return false;
        return true;
    }

    public boolean CreateRoom(String roomID, String playerID, Channel channel) {
        if (!PrepareRooms.containsKey(roomID)) return false;

        Room room = new Room(PrepareRooms.get(roomID), playerID, channel);
        ChannelRoomMapping.put(channel.id(), roomID);
        Rooms.put(roomID, room);
        PrepareRooms.remove(roomID);
        return true;
    }

    public boolean HasRoom(String roomID) {
        return Rooms.containsKey(roomID);
    }

    public boolean HasRoom(ChannelId channelID) {
        return ChannelRoomMapping.containsKey(channelID);
    }

    public Room GetRoom(String roomID) {
        return Rooms.get(roomID);
    }

    public Room GetRoom(Channel channel) {
        String roomID = ChannelRoomMapping.get(channel.id());
        if (StringUtils.IsNullOrEmpty(roomID)) return null;
        return Rooms.get(roomID);
    }

    public Room GetRoom(ChannelId channelID) {
        String roomID = ChannelRoomMapping.get(channelID);
        if (StringUtils.IsNullOrEmpty(roomID)) return null;
        return Rooms.get(roomID);
    }

    public List<RoomInfo> GetRoomList() {
        List<RoomInfo> roomInfos = new ArrayList<>();
        for (Room room : Rooms.values()) {
            roomInfos.add(room.toRoomInfo());
        }
        return roomInfos;
    }

    public boolean AddPlayer(String roomID, String playerID) {
        Channel channel = PlayerManager.GetInstance().GetChannel(playerID);
        if (channel == null) return false;

        ChannelRoomMapping.put(channel.id(), roomID);

        Room room = Rooms.get(roomID);
        if (room == null) return false;
        if (room.IsFull()) {
            room.AddPlayer(playerID, channel, PlayerRole.Observer);
        } else {
            room.AddPlayer(playerID, channel, PlayerRole.Competitor);
        }
        return true;
    }

    public void RemovePlayer() {

    }

    public void Remove(ChannelId channelID) {
        ChannelRoomMapping.remove(channelID);
    }

    public void Remove(ChannelGroup channelGroup, Room room) {
        for (Channel channel : channelGroup) {
            ChannelRoomMapping.remove(channel.id());
        }
        Rooms.remove(room.RoomID);
    }
}
